// Copyright 2012 wstc

#include "base/bitmap.h"
#include <stdlib.h>
#include <string.h>

#define BYTES_PER_LONG sizeof(long)  // NOLINT 4
#define BITS_PER_LONG  (BYTES_PER_LONG << 3)
#define BITS_PER_LONG_MASK (BITS_PER_LONG - 1)
#define ALIGN_TO_LONG(sz) (((sz) + BITS_PER_LONG_MASK) / BITS_PER_LONG)
#define GET_INDEX_AND_OFFSET(index, offset, loc) \
  do { \
    (index) = (loc) / BITS_PER_LONG; \
    (offset) = (loc) % BITS_PER_LONG; \
  } while (0)

Bitmap::Bitmap() {
  data_ = NULL;
  data_size_ = 0;
  size_ = 0;
}

Bitmap::Bitmap(size_t size) {
  data_size_ = ALIGN_TO_LONG(size);
  size_ = data_size_ * BITS_PER_LONG;
  data_ = (data_t) malloc(data_size_ * BYTES_PER_LONG);
  memset(data_, 0, data_size_ * BYTES_PER_LONG);
}

size_t Bitmap::Resize(size_t size) {
  if (size < size_) {
    return size_;
  }
  size_t data_size = ALIGN_TO_LONG(size);
  size_ = data_size * BITS_PER_LONG;
  data_ = (data_t) realloc(data_, data_size * BYTES_PER_LONG);
  memset(data_ + data_size_, 0, (data_size - data_size_) * BYTES_PER_LONG);
  data_size_ = data_size;
  return size_;
}

void Bitmap::SetBit(size_t loc) {
  if (loc >= Size()) {
    return;
  }
  size_t index = 0, offset = 0;
  GET_INDEX_AND_OFFSET(index, offset, loc);
  data_[index] |= (1 << offset);
}

void Bitmap::ClearBit(size_t loc) {
  if (loc >= Size()) {
    return;
  }
  size_t index = 0, offset = 0;
  GET_INDEX_AND_OFFSET(index, offset, loc);
  data_[index] &= (~(1 << offset));
}

bool Bitmap::TestBit(size_t loc) {
  if (loc >= Size()) {
    return false;
  }
  size_t index = 0, offset = 0;
  GET_INDEX_AND_OFFSET(index, offset, loc);
  return (data_[index] & (1 << offset));
}

Bitmap::~Bitmap() {
  destory();
}

void Bitmap::destory() {
  if (NULL != data_) {
    free(data_);
    data_ = NULL;
  }
  data_size_ = 0;
  size_ = 0;
}
